home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / APLocation / Sources / MacOS_AppleEventUtils.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-23  |  40.7 KB  |  1,558 lines

  1. /*==================================================================
  2.     File:        MacOS_AppleEventUtils.cpp
  3.  
  4.     Contains:    AppleEvent utility routines.
  5.  
  6.     Written by:    Ed Reed
  7.  
  8.     Copyright:    © 1999 Connectix Corporation
  9. ==================================================================*/
  10.  
  11. #include "MacOS_AppleEventUtils.h"
  12.  
  13. #include "MacOS_Exceptions.h"
  14. #include "MacOS_ConnectixUtils.h"
  15. #include "MacOS_Namespaces.h"
  16. #include "MacOS_UMemory.h"
  17.  
  18. #ifndef __AEOBJECTS__
  19. #include <AEObjects.h>
  20. #endif
  21.  
  22. #ifndef __AEPACKOBJECT__
  23. #include <AEPackObject.h>
  24. #endif
  25.  
  26. #ifndef __FINDERREGISTRY__
  27. #include <FinderRegistry.h>
  28. #endif
  29.  
  30. #ifndef __TEXTUTILS__
  31. #include <TextUtils.h>
  32. #endif
  33.  
  34. #ifndef __RESOURCES__
  35. #include <Resources.h>
  36. #endif
  37.  
  38.  
  39. CTX_Begin_Namespace_MacOS
  40.  
  41.  
  42. /*------------------------------------------------------------------
  43.     ResolveAEParameterList    [internal]
  44.  
  45.     This function resolves a list objects contained within in
  46.     AEListDesc into a list of tokens representing the objects.
  47.  
  48.     Parameters:
  49.         In:        inList            - the source list
  50.                 ioResolvedList    - a NULL descriptor or a list
  51.                                   descriptor to which the token
  52.                                   descriptors will be added
  53.         Out:    ioResolvedList    - the list of resolved token
  54.                                   descriptors
  55.                 (return)        - non-zero indicates an error
  56. ------------------------------------------------------------------*/
  57.  
  58. static OSErr
  59. ResolveAEParameterList(
  60.     const AEDescList *    inList,
  61.     AEDescList *        ioResolvedList,
  62.     SInt16                inFlags)
  63. {
  64.     OSErr status = noErr;
  65.  
  66.     /*
  67.     **    If ioResolvedList is not a list, create a list. (This should only happen
  68.     **    the first time that this function is called to process a list of object
  69.     **    specifiers.) By using one list during the recursive traversal of the
  70.     **    object specifier list we flatten {obj1, {obj2, obj3}} into {tok1, tok2,
  71.     **    tok3} where obj1, obj2 & obj3 are object specifiers and tok1, tok2 &
  72.     **    tok3 are the corresponding object tokens.
  73.     */
  74.     if (ioResolvedList->descriptorType != typeAEList)
  75.     {
  76.         check (ioResolvedList->descriptorType == typeNull);
  77.         status = ::AECreateList(NULL, 0L, false, ioResolvedList);
  78.         check (status == noErr);
  79.     }
  80.  
  81.     if (status == noErr)
  82.     {
  83.         AEDesc theItemDesc;
  84.         SInt16 theIndex = 0;
  85.         AEKeyword theKeyword;
  86.  
  87.         /*
  88.         **    Resolve and add every item of inList to outResolvedList.
  89.         **    (ResolveAEParameter will take care of adding the resolve object
  90.         **    specifier to the list.)
  91.         */
  92.         while ((status = ::AEGetNthDesc(inList, ++theIndex,
  93.                             typeWildCard, &theKeyword, &theItemDesc)) == noErr)
  94.         {
  95.             status = CTX_MacOS::ResolveAEParameter(&theItemDesc, ioResolvedList, inFlags);
  96.             ::AEDisposeDesc(&theItemDesc);
  97.             if (status != noErr)
  98.                 break;
  99.         }
  100.         if (status == errAEDescNotFound)
  101.             status = noErr;
  102.     }
  103.  
  104.     return status;
  105. }
  106.  
  107. /*------------------------------------------------------------------
  108.     ResolveAEParameter
  109.  
  110.     This function resolves a an object contained within in
  111.     AEDesc into a token representing the object.
  112.  
  113.     Parameters:
  114.         In:        inParam            - the source descriptor
  115.                 ioResolvedParam    - a NULL descriptor or a list
  116.                                   descriptor to which the token
  117.                                   descriptors will be added
  118.         Out:    ioResolvedParam    - the [list of] resolved token
  119.                                   descriptor
  120.                 (return)        - non-zero indicates an error
  121. ------------------------------------------------------------------*/
  122.  
  123. OSErr
  124. ResolveAEParameter(
  125.     const AEDesc *    inParam,
  126.     AEDesc *        ioResolvedParam,
  127.     SInt16            inFlags)
  128. {
  129.     OSErr status = noErr;
  130.     AEDesc resolvedParam;
  131.  
  132.     /*
  133.     **    If inParam is an object specifier, call AEResolve() to resolve it
  134.     **    into the appropriate type. If ioResolvedParam is a list, add the
  135.     **    resolved parameter to the list. Otherwise, just return the resolved
  136.     **    parameter in ioResolvedParam.
  137.     **
  138.     **    If inParam is a list, call ResolveAEParamterList() to recursively
  139.     **    resolve every item of the list.
  140.     **
  141.     **    If inParam is neither a list nor an object specifier, copy inParam
  142.     **    to ioResovledParam.
  143.     */
  144.     switch (inParam->descriptorType)
  145.     {
  146.         case typeObjectSpecifier:
  147.             status = ::AEResolve(inParam, inFlags, &resolvedParam);
  148.             if (ioResolvedParam->descriptorType != typeAEList)
  149.                 *ioResolvedParam = resolvedParam;
  150.             else
  151.             {
  152.                 status = ::AEPutDesc(ioResolvedParam, 0, &resolvedParam);
  153.                 check (status == noErr);
  154.                 ::AEDisposeDesc(&resolvedParam);
  155.             }
  156.             break;
  157.         
  158.         case typeAEList:
  159.             status = CTX_MacOS::ResolveAEParameterList(inParam, ioResolvedParam, inFlags);
  160.             break;
  161.         
  162.         default:
  163.             if (ioResolvedParam->descriptorType == typeAEList)
  164.                 status = ::AEPutDesc(ioResolvedParam, 0, inParam);
  165.             else
  166.             {
  167.                 check (ioResolvedParam->descriptorType == typeNull);
  168.                 status = ::AEDuplicateDesc(inParam, ioResolvedParam);
  169.             }
  170.             check (status == noErr);
  171.             break;
  172.     }
  173.     
  174.     return status;
  175. }
  176.  
  177.  
  178. /*------------------------------------------------------------------
  179.     CheckRequiredParams
  180.  
  181.     This function checks for the missed keyword attribute and
  182.     returns errAEParamMissed if it is present.
  183.  
  184.     Parameter:
  185.         In:        inEvent        - AppleEvent descriptor
  186.         Out:    (return)    - errAEParamMissed if missed keyword
  187.                               attribute is present; noErr otherwise
  188. ------------------------------------------------------------------*/
  189.  
  190. OSErr
  191. CheckRequiredParams(
  192.     const AppleEvent * inEvent)
  193. {
  194.     DescType    returnedType;
  195.     long        size;
  196.     
  197.     return (::AEGetAttributePtr(inEvent, keyMissedKeywordAttr,
  198.             typeWildCard, &returnedType, NULL, 0, &size) == errAEDescNotFound)
  199.                 ? noErr
  200.                 : errAEParamMissed;
  201. }
  202.  
  203.  
  204. /*------------------------------------------------------------------
  205.     GetAEErrorNumber
  206.  
  207.     This function checks for the error number attribute and returns
  208.     the attribute's value if present. GetAEErrorNumber returns noErr
  209.     if the error number attribute is not present.
  210.  
  211.     Parameter:
  212.         In:        inEvent        - AppleEvent descriptor
  213.         Out:    (return)    - value of error number attribute if it
  214.                               is present; noErr otherwise
  215. ------------------------------------------------------------------*/
  216.  
  217. SInt32
  218. GetAEErrorNumber(
  219.     const AppleEvent * inEvent)
  220. {
  221.     DescType typeCode;
  222.     Size actualSize;
  223.     SInt32 theErrNumber = 0;
  224.     
  225.     ::AEGetKeyPtr(inEvent, keyErrorNumber, typeLongInteger, &typeCode,
  226.                                 &theErrNumber, sizeof(theErrNumber), &actualSize);
  227.     return theErrNumber;
  228. }
  229.  
  230.  
  231. /*------------------------------------------------------------------
  232.     GetAEParameter
  233.  
  234.     This function returns the resolved descriptor of the specified
  235.     parameter.
  236.  
  237.     Parameter:
  238.         In:        inEvent        - AppleEvent descriptor
  239.                 inKeyword    - parameter keyword
  240.         Out:    outParam    - resolve parameter descriptor
  241.                 (return)    - non-zero indicates an error
  242. ------------------------------------------------------------------*/
  243.  
  244. OSErr
  245. GetAEParameter(
  246.     const AppleEvent *    inEvent,
  247.     AEKeyword            inKeyword,
  248.     AEDesc *            outParam)
  249. {
  250.     /*
  251.     **    Retrieve the parameter specified by inKeyword from inEvent and resolve
  252.     **    any object specifiers.
  253.     */
  254.     OSErr status;
  255.     AEDesc theDesc;
  256.     
  257.     outParam->descriptorType = typeNull;
  258.     outParam->dataHandle = NULL;
  259.     
  260.     status = ::AEGetParamDesc(inEvent, inKeyword, typeWildCard, &theDesc);
  261.     if (status == noErr)
  262.     {
  263.         status = CTX_MacOS::ResolveAEParameter(&theDesc, outParam);
  264.         ::AEDisposeDesc(&theDesc);
  265.     }
  266.     
  267.     return status;
  268. }
  269.  
  270. /*------------------------------------------------------------------
  271.     GetAEBoolean
  272.  
  273.     This function returns the boolean value of the specified
  274.     parameter.
  275.  
  276.     Parameter:
  277.         In:        inEvent        - AppleEvent descriptor
  278.                 inKeyword    - parameter keyword
  279.         Out:    outBoolean    - boolean value of parameter
  280.                 (return)    - non-zero indicates an error
  281. ------------------------------------------------------------------*/
  282.  
  283. OSErr
  284. GetAEBoolean(
  285.     const AppleEvent *    inEvent,
  286.     AEKeyword            inKeyword,
  287.     Boolean *            outBoolean)
  288. {
  289.     OSErr status;
  290.     DescType theTypeCode;
  291.     Size theActualSize;
  292.     
  293.     status = ::AEGetParamPtr(inEvent, inKeyword, typeWildCard,
  294.                                         &theTypeCode, NULL, 0L, &theActualSize);
  295.     if (status == noErr)
  296.     {
  297.         *outBoolean = theTypeCode == typeTrue;
  298.     }
  299.     return status;
  300. }
  301.  
  302.  
  303. /*------------------------------------------------------------------
  304.     GetAppleEventClassAndID
  305.  
  306.     This function returns AppleEvent class and event IDs.
  307.  
  308.     Parameter:
  309.         In:        inEvent        - AppleEvent descriptor
  310.         Out:    outClass    - the AppleEvent class
  311.                 outID        - the AppleEvent event ID
  312.                 (return)    - non-zero indicates an error
  313. ------------------------------------------------------------------*/
  314.  
  315. OSErr
  316. GetAppleEventClassAndID(
  317.     const AppleEvent *    inEvent,
  318.     AEEventClass *        outClass,
  319.     AEEventID *            outID)
  320. {
  321.     OSErr status;
  322.     DescType typeCode;
  323.     Size actualSize;
  324.     
  325.     status = ::AEGetAttributePtr(inEvent, keyEventClassAttr,
  326.                 typeType, &typeCode, outClass, sizeof(AEEventClass), &actualSize);
  327.     require (status == noErr, FailedToGetClass);
  328.     
  329.     status = ::AEGetAttributePtr(inEvent, keyEventIDAttr,
  330.                     typeType, &typeCode, outID, sizeof(AEEventID), &actualSize);
  331.     require (status == noErr, FailedToGetEventID);
  332.  
  333. FailedToGetEventID:
  334. FailedToGetClass:
  335.     return status;
  336. }
  337.  
  338. /*------------------------------------------------------------------
  339.     Get1AEEventHandler
  340.  
  341.     This function returns AppleEvent handler from the specified
  342.     handler table given the class and event IDs.
  343.  
  344.     Parameter:
  345.         In:        inEvent        - AppleEvent descriptor
  346.                 inClass        - the AppleEvent class
  347.                 inID        - the AppleEvent event ID
  348.                 inSysHandler- if true, get the handler from the
  349.                               system table
  350.         Out:    outProc        - the event handler UPP
  351.                 outRefCon    - the event handler reference constant
  352.                 (return)    - non-zero indicates an error
  353. ------------------------------------------------------------------*/
  354.  
  355. OSErr
  356. Get1AEEventHandler(
  357.     AEEventClass        inClass,
  358.     AEEventID            inID,
  359.     AEEventHandlerUPP *    outProc,
  360.     UInt32 *            outRefCon,
  361.     Boolean                inSysHandler)
  362. {
  363.     OSErr status;
  364.     
  365.     if ((status = ::AEGetEventHandler(inClass, inID,
  366.                         outProc, (SInt32*) outRefCon, inSysHandler)) != noErr)
  367.     {
  368.         if ((status = ::AEGetEventHandler(typeWildCard, inID,
  369.                             outProc, (SInt32*) outRefCon, inSysHandler)) != noErr)
  370.         {
  371.             if ((status = ::AEGetEventHandler(inClass, typeWildCard,
  372.                                 outProc, (SInt32*) outRefCon, inSysHandler)) != noErr)
  373.             {
  374.                 status = ::AEGetEventHandler(typeWildCard, typeWildCard,
  375.                                     outProc, (SInt32*) outRefCon, inSysHandler);
  376.             }
  377.         }
  378.     }
  379.     return status;
  380. }
  381.  
  382. /*------------------------------------------------------------------
  383.     GetAEEventHandler
  384.  
  385.     This function returns an AppleEvent handler given the class and
  386.     event IDs. If a handler has not been installed in the
  387.     application handler table, then the system handler table will be
  388.     searched.
  389.  
  390.     Parameter:
  391.         In:        inEvent        - AppleEvent descriptor
  392.                 inClass        - the AppleEvent class
  393.                 inID        - the AppleEvent event ID
  394.         Out:    outProc        - the event handler UPP
  395.                 outRefCon    - the event handler reference constant
  396.                 (return)    - non-zero indicates an error
  397. ------------------------------------------------------------------*/
  398.  
  399. OSErr
  400. GetAEEventHandler(
  401.     AEEventClass        inClass,
  402.     AEEventID            inID,
  403.     AEEventHandlerUPP *    outProc,
  404.     UInt32 *            outRefCon)
  405. {
  406.     OSErr status;
  407.     
  408.     if ((status = CTX_MacOS::Get1AEEventHandler(inClass, inID, outProc, outRefCon, false)) != noErr)
  409.         status = CTX_MacOS::Get1AEEventHandler(inClass, inID, outProc, outRefCon, true);
  410.     
  411.     return status;
  412. }
  413.  
  414.  
  415. /*------------------------------------------------------------------
  416.     Call1AEEventHandler
  417.  
  418.     This function searches for and calls the handler for the given
  419.     AppleEvent class and event ID. Only the system or application
  420.     handler table is searched.
  421.  
  422.     Parameter:
  423.         In:        inClass        - the AppleEvent class
  424.                 inID        - the AppleEvent event ID
  425.                 inEvent        - AppleEvent descriptor
  426.                 ioReply        - a NULL descriptor indicates no reply
  427.                               is desired; otherwise this should
  428.                               point to a kAEAnswer AppleEvent
  429.                 inSysHandler- if true, get the handler from the
  430.                               system table
  431.         Out:    ioReply        - the reply from the event handler
  432.                 (return)    - non-zero indicates an error
  433. ------------------------------------------------------------------*/
  434.  
  435. OSErr
  436. Call1AEEventHandler(
  437.     AEEventClass        inClass,
  438.     AEEventID            inID,
  439.     const AppleEvent *    inEvent,
  440.     AppleEvent *        ioReply,
  441.     Boolean                inSysHandler)
  442. {
  443.     OSErr status;
  444.     
  445.     AEEventHandlerUPP handlerUPP;
  446.     UInt32 handlerRefCon;
  447.     
  448.     status = CTX_MacOS::Get1AEEventHandler(inClass, inID, &handlerUPP, &handlerRefCon, inSysHandler);
  449.     if (status == noErr)
  450.     {
  451.         status = InvokeAEEventHandlerUPP(inEvent, ioReply, handlerRefCon, handlerUPP);
  452.     }
  453.     return status;
  454. }
  455.  
  456.  
  457. /*------------------------------------------------------------------
  458.     CallAEEventHandler
  459.  
  460.     This function searches for and calls the handler for the given
  461.     AppleEvent class and event ID. If the handler is not found in
  462.     the application handler table, the system handler table is
  463.     searched.
  464.  
  465.     Parameter:
  466.         In:        inClass        - the AppleEvent class
  467.                 inID        - the AppleEvent event ID
  468.                 inEvent        - AppleEvent descriptor
  469.                 ioReply        - a NULL descriptor indicates no reply
  470.                               is desired; otherwise this should
  471.                               point to a kAEAnswer AppleEvent
  472.         Out:    ioReply        - the reply from the event handler
  473.                 (return)    - non-zero indicates an error
  474. ------------------------------------------------------------------*/
  475.  
  476. OSErr
  477. CallAEEventHandler(
  478.     AEEventClass        inClass,
  479.     AEEventID            inID,
  480.     const AppleEvent *    inEvent,
  481.     AppleEvent *        ioReply)
  482. {
  483.     OSErr status;
  484.     
  485.     status = CTX_MacOS::Call1AEEventHandler(inClass, inID, inEvent, ioReply, false);
  486.     if (status == errAEHandlerNotFound || status == errAEEventNotHandled)
  487.         status = CTX_MacOS::Call1AEEventHandler(inClass, inID, inEvent, ioReply, true);
  488.     return status;
  489. }
  490.  
  491.  
  492. /*------------------------------------------------------------------
  493.     CopyAppleEventParameters
  494.  
  495.     This function copies the parameters from one AppleEvent to
  496.     another.
  497.  
  498.     Parameter:
  499.         In:        inOriginal    - the source AppleEvent
  500.         Out:    outCopy        - the newly created AppleEvent
  501.                 (return)    - non-zero indicates an error
  502. ------------------------------------------------------------------*/
  503.  
  504. OSErr
  505. CopyAppleEventParameters(
  506.     const AppleEvent *    inOriginal,
  507.     AppleEvent *        outCopy)
  508. {
  509.     OSErr status;
  510.     AEDesc theDesc;
  511.     AEKeyword theKeyword;
  512.     SInt16 index = 1;
  513.     
  514.     while ((status = ::AEGetNthDesc(inOriginal, index++,
  515.                             typeWildCard, &theKeyword, &theDesc)) == noErr)
  516.     {
  517.         status = ::AEPutParamDesc(outCopy, theKeyword, &theDesc);
  518.         check (status == noErr);
  519.         ::AEDisposeDesc(&theDesc);
  520.         if (status != noErr)
  521.             break;
  522.     }
  523.     if (status == errAEDescNotFound)
  524.         status = noErr;
  525.     
  526.     return noErr;
  527. }
  528.  
  529. /*------------------------------------------------------------------
  530.     CreateNamedObjectSpecifier
  531.  
  532.     This function creates an object specifier using the name key
  533.     form.
  534.  
  535.     Parameter:
  536.         In:        inDesiredClass    - the class of the object
  537.                 inContainer        - the object container descriptor
  538.                 inName            - the name of the object
  539.         Out:    outSpecifier    - an object specifier of formName
  540.                 (return)        - non-zero indicates an error
  541. ------------------------------------------------------------------*/
  542.  
  543. OSErr
  544. CreateNamedObjectSpecifier(
  545.     DescType            inDesiredClass,
  546.     const AEDesc *        inContainer,
  547.     ConstStr255Param    inName,
  548.     AEDesc *            outSpecifier)
  549. {
  550.     OSErr status;
  551.     AEDesc theNameKeyDesc;
  552.     
  553.     status = ::AECreateDesc(typeChar, inName + 1, StrLength(inName), &theNameKeyDesc);
  554.     require (status == noErr, FailedToCreateNameDesc);
  555.     
  556.     status = ::CreateObjSpecifier(inDesiredClass,
  557.                  (AEDesc*) inContainer, formName, &theNameKeyDesc, false, outSpecifier);
  558.     check (status == noErr);
  559.     
  560.     ::AEDisposeDesc(&theNameKeyDesc);
  561.  
  562. FailedToCreateNameDesc:
  563.     return status;
  564. }
  565.  
  566. /*------------------------------------------------------------------
  567.     CreateIndexObjectSpecifier
  568.  
  569.     This function creates an object specifier using the absolute
  570.     position key form.
  571.  
  572.     Parameter:
  573.         In:        inDesiredClass    - the class of the object
  574.                 inContainer        - the object container descriptor
  575.                 inIndex            - the index of the object
  576.         Out:    outSpecifier    - an object specifier of formAbsolutePosition
  577.                 (return)        - non-zero indicates an error
  578. ------------------------------------------------------------------*/
  579.  
  580. OSErr
  581. CreateIndexObjectSpecifier(
  582.     DescType        inDesiredClass,
  583.     const AEDesc *    inContainer,
  584.     SInt32            inIndex,
  585.     AEDesc *        outSpecifier)
  586. {
  587.     OSErr status;
  588.     AEDesc theIndexKeyDesc;
  589.     
  590.     status = ::AECreateDesc(typeSInt32, &inIndex, sizeof(inIndex), &theIndexKeyDesc);
  591.     require (status == noErr, FailedToCreateNameDesc);
  592.     
  593.     status = ::CreateObjSpecifier(inDesiredClass,
  594.                  (AEDesc*) inContainer, formAbsolutePosition, &theIndexKeyDesc, false, outSpecifier);
  595.     check (status == noErr);
  596.     
  597.     ::AEDisposeDesc(&theIndexKeyDesc);
  598.  
  599. FailedToCreateNameDesc:
  600.     return status;
  601. }
  602.  
  603. /*------------------------------------------------------------------
  604.     CreateUniqueIDObjectSpecifier
  605.  
  606.     This function creates an object specifier using the unique ID
  607.     key form.
  608.  
  609.     Parameter:
  610.         In:        inDesiredClass    - the class of the object
  611.                 inContainer        - the object container descriptor
  612.                 inUniqueID        - the unique ID of the object
  613.         Out:    outSpecifier    - an object specifier of formName
  614.                 (return)        - non-zero indicates an error
  615. ------------------------------------------------------------------*/
  616.  
  617. OSErr
  618. CreateUniqueIDObjectSpecifier(
  619.     DescType        inDesiredClass,
  620.     const AEDesc *    inContainer,
  621.     SInt32            inUniqueID,
  622.     AEDesc *        outSpecifier)
  623. {
  624.     OSErr status;
  625.     AEDesc theUniqueIDKeyDesc;
  626.     
  627.     status = ::AECreateDesc(typeSInt32, &inUniqueID, sizeof(inUniqueID), &theUniqueIDKeyDesc);
  628.     require (status == noErr, FailedToCreateUniqueIDDesc);
  629.     
  630.     status = ::CreateObjSpecifier(inDesiredClass,
  631.                  (AEDesc*) inContainer, formUniqueID, &theUniqueIDKeyDesc, false, outSpecifier);
  632.     check (status == noErr);
  633.     
  634.     ::AEDisposeDesc(&theUniqueIDKeyDesc);
  635.  
  636. FailedToCreateUniqueIDDesc:
  637.     return status;
  638. }
  639.  
  640. /*------------------------------------------------------------------
  641.     FSMakeFSSpecAndGetInfo    [internal]
  642.  
  643.     This function creates a file system specification record and
  644.     returns a boolean value indicating if this item is a directory.
  645.  
  646.     Parameter:
  647.         In:        inVRefNum    - the volume reference number
  648.                 inParID        - the item's parent directory ID
  649.                 inName        - the item's name
  650.         Out:    outSpec        - the file system specification record
  651.                 outIsFolder    - if true, the item is a folder
  652.                 (return)    - non-zero indicates an error
  653. ------------------------------------------------------------------*/
  654.  
  655. static OSErr
  656. FSMakeFSSpecAndGetInfo(
  657.     SInt16                inVRefNum,
  658.     SInt32                inParID,
  659.     ConstStr255Param    inName,
  660.     FSSpec *            outSpec,
  661.     Boolean *            outIsFolder)
  662. {
  663.     CInfoPBRec catInfo;
  664.     OSErr status;
  665.     
  666.     if ((status = ::MakeFSSpec(inVRefNum, inParID, inName, outSpec)) == noErr
  667.         && (status = ::FSpGetCatInfo(outSpec, &catInfo)) == noErr)
  668.     {
  669.         *outIsFolder = (catInfo.hFileInfo.ioFlAttrib&ioDirMask) != 0;
  670.     }
  671.     return status;
  672. }
  673.  
  674. /*------------------------------------------------------------------
  675.     CreateFSSpecObjectSpecifier
  676.  
  677.     This function creates an object specifier for the specified file
  678.     system object.
  679.  
  680.     Parameter:
  681.         In:        inDesiredClass    - the class of the object or
  682.                                   typeWildcard
  683.                 inContainer        - the object container descriptor
  684.                 inFSSpec        - the FSSpec of the object
  685.         Out:    outSpecifier    - an object specifier of formName
  686.                 (return)        - non-zero indicates an error
  687. ------------------------------------------------------------------*/
  688.  
  689. OSErr
  690. CreateFSSpecObjectSpecifier(
  691.     DescType        inDesiredClass,
  692.     const AEDesc *    inContainer,
  693.     const FSSpec *    inFSSpec,
  694.     AEDesc *        outSpecifier)
  695. {
  696.     OSErr status;
  697.     
  698.     if (inFSSpec->parID == fsRtParID)
  699.     {
  700.         status = CTX_MacOS::CreateNamedObjectSpecifier(
  701.             inDesiredClass == typeWildCard
  702.                 ? cDisk
  703.                 : inDesiredClass,
  704.             inContainer,
  705.             inFSSpec->name,
  706.             outSpecifier);
  707.     }
  708.     else
  709.     {
  710.         FSSpec theParentSpec;
  711.         AEDesc theParentDesc;
  712.         Boolean isFolder;
  713.         
  714.         *theParentSpec.name = 0;
  715.         status = CTX_MacOS::FSMakeFSSpecAndGetInfo(inFSSpec->vRefNum,
  716.             inFSSpec->parID,
  717.             theParentSpec.name,
  718.             &theParentSpec,
  719.             &isFolder);
  720.         require (status == noErr, FailedToCreateParentFSSpec);
  721.         
  722.         status = CTX_MacOS::CreateFSSpecObjectSpecifier(
  723.             theParentSpec.parID != fsRtParID ? cFolder : cDisk,
  724.             inContainer,
  725.             &theParentSpec,
  726.             &theParentDesc);
  727.         require (status == noErr, FailedToCreateParentDesc);
  728.         
  729.         status = CTX_MacOS::CreateNamedObjectSpecifier(
  730.             inDesiredClass == typeWildCard
  731.                 ? (isFolder
  732.                     ? cFolder
  733.                     : cFile)
  734.                 : inDesiredClass,
  735.                         &theParentDesc, inFSSpec->name, outSpecifier);
  736.         
  737.         ::AEDisposeDesc(&theParentDesc);
  738.     
  739.     FailedToCreateParentDesc:
  740.     FailedToCreateParentFSSpec:
  741.         ;
  742.     }
  743.     return status;
  744. }
  745.  
  746. /*------------------------------------------------------------------
  747.     CreatePropertyObjectSpecifier
  748.  
  749.     This function creates an object specifier for the specified
  750.     property.
  751.  
  752.     Parameter:
  753.         In:        inDesiredClass    - the class of the object
  754.                 inContainer        - the object container descriptor
  755.                 inPropertyType    - the property ID
  756.         Out:    outSpecifier    - an object specifier of
  757.                                   formPropertyID
  758.                 (return)        - non-zero indicates an error
  759. ------------------------------------------------------------------*/
  760.  
  761. OSErr
  762. CreatePropertyObjectSpecifier(
  763.     DescType        inDesiredClass,
  764.     const AEDesc *    inContainer,
  765.     DescType        inPropertyType,
  766.     AEDesc *        outSpecifier)
  767. {
  768.     OSErr status;
  769.     AEDesc thePropertyKeyDesc;
  770.     
  771.     status = ::AECreateDesc(typeType, &inPropertyType,
  772.                                 sizeof(inPropertyType), &thePropertyKeyDesc);
  773.     require (status == noErr, FailedToCreatePropertyDesc);
  774.     
  775.     status = ::CreateObjSpecifier(inDesiredClass,
  776.          (AEDesc*) inContainer, formPropertyID, &thePropertyKeyDesc, false, outSpecifier);
  777.     check (status == noErr);
  778.     ::AEDisposeDesc(&thePropertyKeyDesc);
  779.     
  780. FailedToCreatePropertyDesc:
  781.     return status;
  782. }
  783.  
  784.  
  785. /*------------------------------------------------------------------
  786.     AECreateHandleDesc
  787.  
  788.     This function creates an AEDesc of the specified type from the
  789.     data in a handle.
  790.  
  791.     Parameter:
  792.         In:        inType        - the type of descriptor
  793.                 inData        - the descriptor data in a handle
  794.         Out:    outDesc        - the resulting descriptor
  795.                 (return)    - non-zero indicates an error
  796. ------------------------------------------------------------------*/
  797.  
  798. OSErr
  799. AECreateHandleDesc(
  800.     DescType        inType,
  801.     const Handle    inData,
  802.     AEDesc *        outDesc)
  803. {
  804.     OSErr status;
  805.     char hState;
  806.     
  807.     hState = ::HGetState(inData);
  808.     HLock(inData);
  809.     
  810.     status = ::AECreateDesc(inType, *inData, GetHandleSize(inData), outDesc);
  811.     check (status == noErr);
  812.     
  813.     ::HSetState(inData, hState);
  814.     
  815.     return status;
  816. }
  817.  
  818. /*------------------------------------------------------------------
  819.     CreateAliasDescriptorFromFSSpec
  820.  
  821.     This function creates an alias descriptor given a file system
  822.     specification record.
  823.  
  824.     Parameter:
  825.         In:        inFSSpec    - the target file system object
  826.         Out:    outDesc        - an alias descriptor
  827.                 (return)    - non-zero indicates an error
  828. ------------------------------------------------------------------*/
  829.  
  830. OSErr
  831. CreateAliasDescriptorFromFSSpec(
  832.     const FSSpec *    inFSSpec,
  833.     AEDesc *        outDesc)
  834. {
  835.     AliasHandle alias;
  836.     OSErr status;
  837.     
  838.     status = ::NewAliasMinimal(inFSSpec, &alias);
  839.     require (status == noErr, NewAliasMinimalFailed);
  840.     
  841.     status = CTX_MacOS::CreateAliasDescriptorFromAlias(alias, outDesc);
  842.     require (status == noErr, CreateAliasDescriptorFailed);
  843.     
  844.     return noErr;
  845.  
  846. CreateAliasDescriptorFailed:
  847.     ::DisposeHandle(reinterpret_cast<Handle>(alias));
  848.  
  849. NewAliasMinimalFailed:
  850.     return status;
  851. }
  852.  
  853.  
  854. /*------------------------------------------------------------------
  855.     CoerceDescList    [internal]
  856.  
  857.     This function coerces every element of a list to the specfied
  858.     type.
  859.  
  860.     Parameter:
  861.         In:        inDescList        - the list of objects
  862.                 inDesiredType    - the type to which to coerce
  863.         Out:    outResult        - the list of coerced objects
  864.                 (return)        - non-zero indicates an error
  865. ------------------------------------------------------------------*/
  866.  
  867. static OSErr
  868. CoerceDescList(
  869.     const AEDesc *    inDescList,
  870.     DescType        inDesiredType,
  871.     AEDesc *        outResult)
  872. {
  873.     OSErr status = noErr;
  874.     AEDesc theDesc;
  875.     SInt16 theIndex = 1;
  876.     AEKeyword theKeyword;
  877.     
  878.     status = ::AECreateList(NULL, 0L, false, outResult);
  879.     require (status == noErr, FailedToCreateList);
  880.  
  881.     while ((status = ::AEGetNthDesc(inDescList, theIndex++,
  882.                 typeWildCard, &theKeyword, &theDesc)) == noErr)
  883.     {
  884.         AEDesc theCoercedDesc = { typeNull, NULL };
  885.         
  886.         status = CTX_MacOS::CoerceDesc(&theDesc, inDesiredType, &theCoercedDesc);
  887.         ::AEDisposeDesc(&theDesc);
  888.         if (status != noErr)
  889.             break;
  890.         
  891.         status = ::AEPutDesc(outResult, 0, &theCoercedDesc);
  892.         check (status == noErr);
  893.         ::AEDisposeDesc(&theCoercedDesc);
  894.         if (status != noErr)
  895.             break;
  896.     }
  897.     if (status == errAEDescNotFound)
  898.         status = noErr;
  899.     else if (status != noErr)
  900.         AEDisposeDesc(outResult);
  901.  
  902. FailedToCreateList:
  903.     return status;
  904. }
  905.  
  906. /*------------------------------------------------------------------
  907.     CoerceDesc
  908.  
  909.     This function coerce the specified descriptor to the specfied
  910.     type. If the initial coercion fails and the descriptor is list,
  911.     the function coerces each item of the list.
  912.  
  913.     Parameter:
  914.         In:        inDesc            - the descriptor to coerce
  915.                 inDesiredType    - the type to which to coerce
  916.         Out:    outResult        - the coerced object or list of
  917.                                   coerced objects
  918.                 (return)        - non-zero indicates an error
  919. ------------------------------------------------------------------*/
  920.  
  921. OSErr
  922. CoerceDesc(
  923.     const AEDesc *    inDesc,
  924.     DescType        inDesiredType,
  925.     AEDesc *        outResult)
  926. {
  927.     OSErr status;
  928.     
  929.     status = ::AECoerceDesc(inDesc, inDesiredType, outResult);
  930.     if (status == errAECoercionFail)
  931.     {
  932.         if (inDesc->descriptorType == typeAEList)
  933.             status = CTX_MacOS::CoerceDescList(inDesc, inDesiredType, outResult);
  934.     }
  935.     check (status == noErr);
  936.     
  937.     return status;
  938. }
  939.  
  940. /*------------------------------------------------------------------
  941.     CompareDescs
  942.  
  943.     This function compares two blocks of bytes. If the first block
  944.     is greater than the second, the result is positive. If the
  945.     converse is true. the result is negative. If the blocks are
  946.     equal, the result is zero.
  947.  
  948.     Parameters:
  949.         In:        inSource        - the source descriptor
  950.                 inDest            - the destination descriptor
  951.         Out:    outResult        - positive if 1st > 2nd;
  952.                                   negative if 1st < 2nd;
  953.                                   zero if equal
  954.                 (return)        - non-zero if descs are not
  955.                                   comparable; noErr otherwise
  956. ------------------------------------------------------------------*/
  957.  
  958. OSErr
  959. CompareDescs(
  960.     const AEDesc *    inSource,
  961.     const AEDesc *    inDest,
  962.     SInt32 *        outResult)
  963. {
  964.     OSErr status = noErr;
  965.     AEKeyword keyword;
  966.     
  967.     // If the descriptor types are not the same, first attempt to coerce
  968.     // the destination descriptor to the source descriptor type and then
  969.     // compare the two descriptors. If this coercion fails attempt to
  970.     // coerce the source descriptor to the destination descriptor type
  971.     // and then compare the two descriptors. We do this because many
  972.     // coercions are unidirectional. E.g. typeBoolean --> typeTrue only
  973.     // if the boolean value is 1; typeTrue --> typeBoolean always succeeds.
  974.     if (inSource->descriptorType != inDest->descriptorType)
  975.     {
  976.         AEDesc coercedDesc = {typeNull, NULL};
  977.         
  978.         status = ::AECoerceDesc(inDest, inSource->descriptorType, &coercedDesc);
  979.         if (status == noErr)
  980.             status = CTX_MacOS::CompareDescs(inSource, &coercedDesc, outResult);
  981.         else
  982.         {
  983.             require (status == errAECoercionFail, FatalError);
  984.             
  985.             status = ::AECoerceDesc(inSource, inDest->descriptorType, &coercedDesc);
  986.             if (status == noErr)
  987.                 status = CTX_MacOS::CompareDescs(&coercedDesc, inDest, outResult);
  988.             else
  989.             {
  990.                 require (status == errAECoercionFail, FatalError);
  991.                 
  992.                 // Since we can't coerce descriptors typeTrue <==> typeFalse
  993.                 // but we can make a valid comparison with these two, special
  994.                 // case the comparison here.
  995.                 if ((inSource->descriptorType == typeTrue || inSource->descriptorType == typeFalse)
  996.                     && (inDest->descriptorType == typeTrue || inDest->descriptorType == typeFalse))
  997.                 {
  998.                     // Always false because we can only get here if the descriptor
  999.                     // types are not equal to begin with.
  1000.                     *outResult = false;
  1001.                     status = noErr;
  1002.                 }
  1003.             }
  1004.         }
  1005.         
  1006.         ::AEDisposeDesc(&coercedDesc);
  1007.     }
  1008.     else
  1009.     {
  1010.         switch (inSource->descriptorType)
  1011.         {
  1012.             case typeAEList:
  1013.             {
  1014.                 SInt32 sourceCount;
  1015.                 SInt32 destCount;
  1016.                 SInt32 count;
  1017.                 
  1018.                 status = ::AECountItems(inSource, &sourceCount);
  1019.                 require (status == noErr, CantGetItemCount);
  1020.                 status = ::AECountItems(inDest, &destCount);
  1021.                 require (status == noErr, CantGetItemCount);
  1022.                 
  1023.                 count = ::Min32(sourceCount, destCount);
  1024.                 for (SInt32 index = 1; index <= count; index++)
  1025.                 {
  1026.                     AEDesc sourceItem;
  1027.                     AEDesc destItem;
  1028.                     
  1029.                     status = ::AEGetNthDesc(inSource, index, typeWildCard, &keyword, &sourceItem);
  1030.                     require (status == noErr, CantGetItemDesc);
  1031.                     
  1032.                     status = ::AEGetNthDesc(inSource, index, typeWildCard, &keyword, &destItem);
  1033.                     require_action (status == noErr, CantGetItemDesc, ::AEDisposeDesc(&sourceItem););
  1034.                     
  1035.                     status = CTX_MacOS::CompareDescs(&sourceItem, &destItem, outResult);
  1036.                     ::AEDisposeDesc(&sourceItem);
  1037.                     ::AEDisposeDesc(&destItem);
  1038.                     require (status == noErr, CantCompareItemDescs);
  1039.                     if (*outResult != 0)
  1040.                         break;
  1041.                 }
  1042.                 if (*outResult == 0)
  1043.                     *outResult = sourceCount - destCount;
  1044.             
  1045.             CantCompareItemDescs:
  1046.             CantGetItemDesc:
  1047.             CantGetItemCount:
  1048.                 break;
  1049.             }
  1050.             
  1051.             case typeAERecord:
  1052.             {
  1053.                 SInt32 sourceKeys;
  1054.                 SInt32 destKeys;
  1055.                 SInt32 count;
  1056.  
  1057.                 status = ::AECountItems(inSource, &sourceKeys);
  1058.                 require (status == noErr, CantGetKeyCount);
  1059.                 status = ::AECountItems(inDest, &destKeys);
  1060.                 require (status == noErr, CantGetKeyCount);
  1061.  
  1062.                 count = ::Min32(sourceKeys, destKeys);
  1063.                 for (SInt32 index = 1; index <= count; index++)
  1064.                 {
  1065.                     AEDesc sourceKey;
  1066.                     AEDesc destKey;
  1067.  
  1068.                     status = ::AEGetNthDesc(inSource, index, typeWildCard, &keyword, &sourceKey);
  1069.                     require (status == noErr, CantGetKeyDesc);
  1070.  
  1071.                     status = ::AEGetKeyDesc(inDest, keyword, typeWildCard, &destKey);
  1072.                     require_action (status == noErr, CantGetKeyDesc, ::AEDisposeDesc(&sourceKey););
  1073.  
  1074.                     status = CTX_MacOS::CompareDescs(&sourceKey, &destKey, outResult);
  1075.                     ::AEDisposeDesc(&sourceKey);
  1076.                     ::AEDisposeDesc(&destKey);
  1077.                     require (status == noErr, CantCompareKeyDescs);
  1078.                     if (*outResult != 0)
  1079.                         break;
  1080.                 }
  1081.                 if (*outResult == 0)
  1082.                     *outResult = sourceKeys - destKeys;
  1083.  
  1084.             CantCompareKeyDescs:
  1085.             CantGetKeyDesc:
  1086.             CantGetKeyCount:
  1087.                 break;
  1088.             }
  1089.             
  1090.             default:
  1091.             {
  1092.                 // If the data handles are both NULL, compare the descriptor types
  1093.                 if (inSource->dataHandle == NULL && inDest->dataHandle == NULL)
  1094.                 {
  1095.                     // Always true because we can only get here if the types are equal
  1096.                     *outResult = true;
  1097.                 }
  1098.                 else
  1099.                 {
  1100.                     StHandleDisposer source(::NewHandle(0));
  1101.                     StHandleDisposer dest(::NewHandle(0));
  1102.                     
  1103.                     require_action(inSource->dataHandle != NULL, FatalError, status = errAENotAEDesc;);
  1104.                     require_action(inDest->dataHandle != NULL, FatalError, status = errAENotAEDesc;);
  1105.                     
  1106.                     CTX_MacOS::GetAEDescData(*inSource, source);
  1107.                     CTX_MacOS::GetAEDescData(*inDest, dest);
  1108.                     
  1109.                     StHandleLocker lockSource(source);
  1110.                     StHandleLocker lockDest(dest);
  1111.                     
  1112.                     *outResult = ::CompareBytes(*source, *dest,
  1113.                                     ::Min32(::GetHandleSize(source), ::GetHandleSize(dest)));
  1114.                     if (*outResult == 0)
  1115.                         *outResult = ::GetHandleSize(source) - ::GetHandleSize(dest);
  1116.                 }
  1117.                 break;
  1118.             }
  1119.         }
  1120.     }
  1121.  
  1122. FatalError:
  1123.     return status;
  1124. }
  1125.  
  1126. /*------------------------------------------------------------------
  1127.     AEStartsWith
  1128.  
  1129.     This function determines if the source descriptor starts with
  1130.     the destination descriptor.
  1131.  
  1132.     Parameters:
  1133.         In:        inSource        - the source descriptor
  1134.                 inDest            - the destination descriptor
  1135.         Out:    outResult        - positive if 1st > 2nd;
  1136.                                   negative if 1st < 2nd;
  1137.                                   zero if equal
  1138.                 (return)        - non-zero if descs are not
  1139.                                   comparable; noErr otherwise
  1140. ------------------------------------------------------------------*/
  1141.  
  1142. OSErr
  1143. AEStartsWith(
  1144.     const AEDesc *    inSource,
  1145.     const AEDesc *    inDest,
  1146.     Boolean *        outResult)
  1147. {
  1148.     OSErr status = noErr;
  1149.     AEKeyword keyword;
  1150.     SInt32 comparisonResult;
  1151.     
  1152.     *outResult = false;
  1153.     
  1154.     switch (inSource->descriptorType)
  1155.     {
  1156.         case typeAEList:
  1157.         {
  1158.             AEDesc sourceItem;
  1159.             
  1160.             status = ::AEGetNthDesc(inSource, 1, typeWildCard, &keyword, &sourceItem);
  1161.             require (status == noErr, CantGetItemDesc);
  1162.             
  1163.             status = CTX_MacOS::CompareDescs(&sourceItem, inDest, &comparisonResult);
  1164.             ::AEDisposeDesc(&sourceItem);
  1165.             require (status == noErr, CantCompareItemDescs);
  1166.             
  1167.             *outResult = comparisonResult == 0;
  1168.         
  1169.         CantCompareItemDescs:
  1170.         CantGetItemDesc:
  1171.             break;
  1172.         }
  1173.         break;
  1174.         
  1175.         case typeChar:
  1176.         {
  1177.             StHandleDisposer source(::NewHandle(0));
  1178.             StHandleDisposer dest(::NewHandle(0));
  1179.             
  1180.             require_action (inSource->descriptorType == inDest->descriptorType, CantCompareDescs, status = errAEEventNotHandled;);
  1181.             
  1182.             CTX_MacOS::GetAEDescData(*inSource, source);
  1183.             CTX_MacOS::GetAEDescData(*inDest, dest);
  1184.             
  1185.             if (::GetHandleSize(dest) <= ::GetHandleSize(source))
  1186.             {
  1187.                 StHandleLocker lockSource(source);
  1188.                 StHandleLocker lockDest(dest);
  1189.                 
  1190.                 comparisonResult = ::CompareBytes(*source, *dest, ::GetHandleSize(dest));
  1191.                 *outResult = comparisonResult == 0;
  1192.             }
  1193.         
  1194.         CantCompareDescs:
  1195.             break;
  1196.         }
  1197.         
  1198.         default:
  1199.             debug_unexpected_value();
  1200.             status = errAEEventNotHandled;
  1201.             break;
  1202.     }
  1203.     
  1204.     return status;
  1205. }
  1206.  
  1207. /*------------------------------------------------------------------
  1208.     AEStartsWith
  1209.  
  1210.     This function determines if the source descriptor ends with
  1211.     the destination descriptor.
  1212.  
  1213.     Parameters:
  1214.         In:        inSource        - the source descriptor
  1215.                 inDest            - the destination descriptor
  1216.         Out:    outResult        - positive if 1st > 2nd;
  1217.                                   negative if 1st < 2nd;
  1218.                                   zero if equal
  1219.                 (return)        - non-zero if descs are not
  1220.                                   comparable; noErr otherwise
  1221. ------------------------------------------------------------------*/
  1222.  
  1223. OSErr
  1224. AEEndsWith(
  1225.     const AEDesc *    inSource,
  1226.     const AEDesc *    inDest,
  1227.     Boolean *        outResult)
  1228. {
  1229.     OSErr status = noErr;
  1230.     AEKeyword keyword;
  1231.     SInt32 comparisonResult;
  1232.     
  1233.     *outResult = false;
  1234.     
  1235.     switch (inSource->descriptorType)
  1236.     {
  1237.         case typeAEList:
  1238.         {
  1239.             AEDesc sourceItem;
  1240.             SInt32 sourceCount;
  1241.             
  1242.             status = ::AECountItems(inSource, &sourceCount);
  1243.             require (status == noErr, CantGetItemCount);
  1244.             
  1245.             status = ::AEGetNthDesc(inSource, sourceCount, typeWildCard, &keyword, &sourceItem);
  1246.             require (status == noErr, CantGetItemDesc);
  1247.             
  1248.             status = CTX_MacOS::CompareDescs(&sourceItem, inDest, &comparisonResult);
  1249.             ::AEDisposeDesc(&sourceItem);
  1250.             require (status == noErr, CantCompareItemDescs);
  1251.             
  1252.             *outResult = comparisonResult == 0;
  1253.         
  1254.         CantCompareItemDescs:
  1255.         CantGetItemDesc:
  1256.         CantGetItemCount:
  1257.             break;
  1258.         }
  1259.         
  1260.         case typeChar:
  1261.         {
  1262.             StHandleDisposer source(::NewHandle(0));
  1263.             StHandleDisposer dest(::NewHandle(0));
  1264.             
  1265.             require_action (inSource->descriptorType == inDest->descriptorType, CantCompareDescs, status = errAEEventNotHandled;);
  1266.             
  1267.             if (CTX_MacOS::GetAEDescDataSize(*inDest) <= CTX_MacOS::GetAEDescDataSize(*inSource))
  1268.             {
  1269.                 CTX_MacOS::GetAEDescData(*inSource, source);
  1270.                 CTX_MacOS::GetAEDescData(*inDest, dest);
  1271.                 
  1272.                 *outResult = ::BytesMatch(source + (::GetHandleSize(source) - ::GetHandleSize(dest)),
  1273.                                 dest, ::GetHandleSize(dest));
  1274.             }
  1275.         
  1276.         CantCompareDescs:
  1277.             break;
  1278.         }
  1279.         break;
  1280.         
  1281.         default:
  1282.             debug_unexpected_value();
  1283.             status = errAEEventNotHandled;
  1284.             break;
  1285.     }
  1286.     
  1287.     return status;
  1288. }
  1289.  
  1290. /*------------------------------------------------------------------
  1291.     AEContains
  1292.  
  1293.     This function determines if the source descriptor contains with
  1294.     the destination descriptor.
  1295.  
  1296.     Parameters:
  1297.         In:        inSource        - the source descriptor
  1298.                 inDest            - the destination descriptor
  1299.         Out:    outResult        - positive if 1st > 2nd;
  1300.                                   negative if 1st < 2nd;
  1301.                                   zero if equal
  1302.                 (return)        - non-zero if descs are not
  1303.                                   comparable; noErr otherwise
  1304. ------------------------------------------------------------------*/
  1305.  
  1306. OSErr
  1307. AEContains(
  1308.     const AEDesc *    inSource,
  1309.     const AEDesc *    inDest,
  1310.     Boolean *        outResult)
  1311. {
  1312.     OSErr status = noErr;
  1313.     AEKeyword keyword;
  1314.     SInt32 comparisonResult;
  1315.     
  1316.     *outResult = false;
  1317.     
  1318.     switch (inSource->descriptorType)
  1319.     {
  1320.         case typeAEList:
  1321.         {
  1322.             SInt32 sourceCount;
  1323.             
  1324.             status = ::AECountItems(inSource, &sourceCount);
  1325.             require (status == noErr, CantGetItemCount);
  1326.             
  1327.             for (SInt32 index = 1; index <= sourceCount; index++)
  1328.             {
  1329.                 AEDesc sourceItem;
  1330.                 
  1331.                 status = ::AEGetNthDesc(inSource, index, typeWildCard, &keyword, &sourceItem);
  1332.                 require (status == noErr, CantGetItemDesc);
  1333.                 
  1334.                 status = CTX_MacOS::CompareDescs(&sourceItem, inDest, &comparisonResult);
  1335.                 ::AEDisposeDesc(&sourceItem);
  1336.                 require (status == noErr, CantCompareItemDescs);
  1337.                 
  1338.                 *outResult = comparisonResult == 0;
  1339.                 if (*outResult)
  1340.                     break;
  1341.             }
  1342.         
  1343.         CantCompareItemDescs:
  1344.         CantGetItemDesc:
  1345.         CantGetItemCount:
  1346.             break;
  1347.         }
  1348.         
  1349.         case typeChar:
  1350.         {
  1351.             StHandleDisposer source;
  1352.             StHandleDisposer dest;
  1353.             
  1354.             require_action (inSource->descriptorType == inDest->descriptorType, CantCompareDescs, status = errAEEventNotHandled;);
  1355.             
  1356.             if (CTX_MacOS::GetAEDescDataSize(*inDest) <= CTX_MacOS::GetAEDescDataSize(*inSource))
  1357.             {
  1358.                 SInt32 count = CTX_MacOS::GetAEDescDataSize(*inSource) - CTX_MacOS::GetAEDescDataSize(*inDest);
  1359.                 
  1360.                 CTX_MacOS::GetAEDescData(*inSource, source);
  1361.                 CTX_MacOS::GetAEDescData(*inDest, dest);
  1362.                 
  1363.                 for (SInt32 offset = 0; offset <= count; offset++)
  1364.                 {
  1365.                     *outResult = ::BytesMatch(source + offset, dest, ::GetHandleSize(dest));
  1366.                     if (*outResult)
  1367.                         break;
  1368.                 }
  1369.             }
  1370.         
  1371.         CantCompareDescs:
  1372.             break;
  1373.         }
  1374.         break;
  1375.         
  1376.         default:
  1377.             debug_unexpected_value();
  1378.             status = errAEEventNotHandled;
  1379.             break;
  1380.     }
  1381.     
  1382.     return status;
  1383. }
  1384.  
  1385. /*------------------------------------------------------------------
  1386.     SetReplyError
  1387.  
  1388.     This function sets the keyErrorNumber and keyErrorString keyword
  1389.     values in the specified Apple Event reply.
  1390.  
  1391.     Parameters:
  1392.         In:        inReply            - a reply Apple Event
  1393.                 inErrorNumber    - the error number
  1394.                 inErrorStrID    - the error message STR# or STR ID
  1395.                 inErrorIndex    - the error index (0 if resource is
  1396.                                     a STR resource)
  1397.         Out:    (return)        - non-zero indicates an error
  1398. ------------------------------------------------------------------*/
  1399.  
  1400. OSErr
  1401. SetReplyError(
  1402.     AppleEvent *    inReply,
  1403.     SInt32            inErrorNumber,
  1404.     SInt16            inErrorStrID,
  1405.     SInt16            inErrorIndex)
  1406. {
  1407.     Str255 message;
  1408.     
  1409.     if (inErrorIndex != 0)
  1410.         ::GetIndString(message, inErrorStrID, inErrorIndex);
  1411.     else
  1412.     {
  1413.         Handle resource = ::GetResource('STR ', inErrorStrID);
  1414.         if (resource == NULL)
  1415.         {
  1416.             message[0] = 0;
  1417.         }
  1418.         else
  1419.         {
  1420.             ::BlockMoveData(*resource, message, StrLength(reinterpret_cast<StringPtr>(*resource)) + 1);
  1421.             ::ReleaseResource(resource);
  1422.         }
  1423.     }
  1424.     
  1425.     return SetReplyError(inReply, inErrorNumber, message);
  1426. }
  1427.  
  1428. /*------------------------------------------------------------------
  1429.     SetReplyError
  1430.  
  1431.     This function sets the keyErrorNumber and keyErrorString keyword
  1432.     values in the specified Apple Event reply.
  1433.  
  1434.     Parameters:
  1435.         In:        inReply            - a reply Apple Event
  1436.                 inErrorNumber    - the error number
  1437.                 inErrorStr        - the error string
  1438.         Out:    (return)        - non-zero indicates an error
  1439. ------------------------------------------------------------------*/
  1440.  
  1441. OSErr
  1442. SetReplyError(
  1443.     AppleEvent *        inReply,
  1444.     SInt32                inErrorNumber,
  1445.     ConstStr255Param    inErrorStr)
  1446. {
  1447.     OSErr status;
  1448.     
  1449.     status = ::AEPutKeyPtr(inReply, keyErrorNumber, typeSInt32, &inErrorNumber, sizeof(inErrorNumber));
  1450.     require (status == noErr, FatalError);
  1451.     
  1452.     if (StrLength(inErrorStr) != 0)
  1453.     {
  1454.         status = ::AEPutKeyPtr(inReply, keyErrorString, typeChar, &inErrorStr[1], StrLength(inErrorStr));
  1455.         require (status == noErr, FatalError);
  1456.     }
  1457.  
  1458. FatalError:
  1459.     return status;
  1460. }
  1461.  
  1462.  
  1463. /*------------------------------------------------------------------
  1464.     GetAEDescData
  1465.  
  1466.     This function retrieves the data from an AEDesc (the dataHandle
  1467.     pre-Carbon). The caller must pass in a valid handle, which will
  1468.     be resized as necessary.
  1469.  
  1470.     Parameters:
  1471.         In:        inDesc                - an AEDesc
  1472.                 ioData                - the data buffer
  1473.         Out:    (return)            - non-zero indicates an error
  1474. ------------------------------------------------------------------*/
  1475.  
  1476. OSErr
  1477. GetAEDescData(
  1478.     const AEDesc &    inDesc,
  1479.     Handle            ioData)
  1480. {
  1481.     ::SetHandleSize(ioData, CTX_MacOS::GetAEDescDataSize(inDesc));
  1482.     return CTX_MacOS::GetAEDescData(inDesc, *ioData, ::GetHandleSize(ioData));
  1483. }
  1484.  
  1485.  
  1486. /*------------------------------------------------------------------
  1487.     GetAEDescData
  1488.  
  1489.     This function retrieves the data from an AEDesc (the dataHandle
  1490.     pre-Carbon).  The caller must pass in the data buffer and its
  1491.     size.
  1492.  
  1493.     Parameters:
  1494.         In:        inDesc                - an AEDesc
  1495.                 outData                - the data buffer
  1496.                 inSize                - the data size
  1497.         Out:    (return)            - non-zero indicates an error
  1498. ------------------------------------------------------------------*/
  1499.  
  1500. OSErr
  1501. GetAEDescData(
  1502.     const AEDesc &    inDesc,
  1503.     void *            outData,
  1504.     UInt32            inSize)
  1505. {
  1506.     if (inDesc.dataHandle == NULL || outData == NULL)
  1507.         return paramErr;
  1508.     
  1509. #if TARGET_API_MAC_CARBON
  1510.     return ::AEGetDescData(&inDesc, outData, UMin32(inSize, ::AEGetDescDataSize(&inDesc)));
  1511. #else
  1512.     ::BlockMoveData(*(inDesc.dataHandle), outData, UMin32(inSize, ::GetHandleSize(inDesc.dataHandle)));
  1513.     return noErr;
  1514. #endif
  1515. }
  1516.  
  1517.  
  1518. /*------------------------------------------------------------------
  1519.     SetAEDescData
  1520.  
  1521.     This function replaces the data in an AEDesc (the dataHandle
  1522.     pre-Carbon).
  1523.  
  1524.     Parameters:
  1525.         In:        descriptor        - an AEDesc
  1526.                 type                - the data type
  1527.                 data                - the data buffer
  1528.                 datasize            - the data size
  1529.         Out:    (return)            - non-zero indicates an error
  1530. ------------------------------------------------------------------*/
  1531.  
  1532. OSErr
  1533. SetAEDescData(
  1534.     AEDesc &         ioDesc,
  1535.     DescType        inType,
  1536.     const void *    inData,
  1537.     UInt32            inSize)
  1538. {
  1539. #if TARGET_API_MAC_CARBON
  1540.     return ::AEReplaceDescData(inType, inData, inSize, &ioDesc);
  1541. #else
  1542.     ioDesc.descriptorType = inType;
  1543.     ::SetHandleSize(ioDesc.dataHandle, inSize);
  1544.     ::BlockMoveData(inData, *(ioDesc.dataHandle), inSize);
  1545.     return noErr;
  1546. #endif
  1547. }
  1548.  
  1549.  
  1550. CTX_End_Namespace_MacOS
  1551.  
  1552.  
  1553. /*==================================================================
  1554.     Change History (most recent first):
  1555.  
  1556.     $Log: MacOS_AppleEventUtils.cpp,v $
  1557. ==================================================================*/
  1558.